//
// Advanced Java Programming
// TIEI - Fall 2024
//
package tiei.ajp.huffman;

import tiei.ajp.huffman.utils.*;
import tiei.ajp.huffman.utils.FileReader;

import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * A class to uncompress a file
 */
public class UncompressFile {

    File inFile = null;
    File outFile = null;

    public UncompressFile(File inputFile, File outputFile) {
        this.inFile = inputFile;
        this.outFile = outputFile;
    }

    /**
     * Return an UncompressFile object to uncompress 'inFile' into 'outFile'
     */
    public static void uncompressFile(File inputFile, File outputFile) throws IOException {
        FileReader fileReader = new FileReader(inputFile);
        FileOutputStream oFile = new FileOutputStream(outputFile);
        // --- Check magic num
        long magicNum = fileReader.readMagicNum();
        if (magicNum != 123456789L) throw new IOException("Invalid file format");
        // --- Unserialize tree & encoding map
        List<Byte> serializedTree = fileReader.readTree();
        HuffmanTree<Byte> tree = new HuffmanTree<>(serializedTree);
        HuffmanEncoder<Byte> hfe = new HuffmanEncoder<Byte>();
        Map<Byte, String> encMap = hfe.encode(tree.getTreeRoot());
        Map<String, Byte> decMap = hfe.getDecodeMap();

        // --- Read bits
        long bitNum = fileReader.readBitNum();
        // --- Uncompress file
        StringBuilder sb = new StringBuilder();
        for (long i = 0L; i < bitNum; i++) {
            int bit = fileReader.readBit();
            if (bit != FileReader.BIT_O && bit != FileReader.BIT_1) throw new IOException("Invalid file");
            sb.append(bit == FileReader.BIT_O ? '0' : '1');
            // Try decoding
            if (decMap.containsKey(sb.toString())) {
                oFile.write((int) decMap.get(sb.toString()));
                sb = new StringBuilder(); // Clear sb
            }
        }


        oFile.flush();
        oFile.close();
    }

    /**
     * Uncompress the file
     */
    public void uncompress() throws IOException {
        uncompressFile(this.inFile, this.outFile);
    }
}
